// +build ignore

package main

import (
	"code.google.com/p/go8/chip8"
	"code.google.com/p/go8/display"
	"code.google.com/p/go8/engine"
	"code.google.com/p/go8/games"
	"code.google.com/p/go8/sdl2_impl"
	"fmt"
	"github.com/gonutz/go-sdl2/sdl"
	_ "time"
)

var window *sdl.Window
var renderer *sdl.Renderer
var game *games.Game
var fonts sdl2_impl.Fonts

func main() {
	err := setupSdl()
	if err != nil {
		return
	}
	defer closeSdl()

	//err = fonts.Init()
	//if err != nil {
	//	panic(err)
	//}
	//defer fonts.Release()

	rand := sdl2_impl.RandomNumber{}
	rand.SeedWithNow()

	keyboard := sdl2_impl.NewKeyboard()

	speakers := sdl2_impl.NewSpeakers(window)
	speakers.Init()
	defer speakers.Release()

	runner := chip8.NewRunner(&interpreterFactory{
		randomizer: rand,
		keyboard:   keyboard,
		keyEvent:   keyboard,
		speakers:   speakers,
	}, tickerFactory{})

	painter := sdl2_impl.NewPainter(renderer, window)
	screenPainter := display.NewScreenPainter(painter)

	e := engine.NewEngine()
	menuPainter := sdl2_impl.NewMenuPainter(renderer, &fonts)
	defer menuPainter.ReleaseAllTextures()
	menus := make([]*engine.GameMenu, len(games.AllGames))
	for i, g := range games.AllGames {
		g = g.FillEmptyData()
		menus[i] = engine.NewGameMenu(e, g, menuPainter, painter)
		gameState := engine.NewGameState(e, g, runner, screenPainter)
		gameState.SetMenuState(menus[i])
		gameState.SetKeyMapCallback(func(g *games.Game) { keyboard.SetKeyMap(g.Keys) })
		menus[i].SetGameState(gameState)
		menus[i].CreateMenuScreen()
	}
	for i := range menus {
		next := (i + 1) % len(menus)
		previous := (i + len(menus) - 1) % len(menus)
		menus[i].SetNextMenu(menus[next])
		menus[i].SetPreviousMenu(menus[previous])
	}
	e.ChangeState(menus[0])
	e.Run()

	var info sdl.RendererInfo
	renderer.GetRendererInfo(&info)
	if info.Flags&sdl.RENDERER_TARGETTEXTURE == 0 {
		fmt.Println("does not have RENDERER_TARGETTEXTURE")
	}

	go func() {
		for {
			if err := sdl.GetError(); err != nil {
				fmt.Println(err)
				sdl.ClearError()
			}
			sdl.Delay(1)
		}
	}()

	for e.Running() {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			e.HandleEvent(event)
			switch e := event.(type) {
			case *sdl.KeyDownEvent:
				if e.Keysym.Sym == sdl.K_F1 {
					maximizeWindow()
				}
				if e.Keysym.Sym == sdl.K_F2 {
					restoreWindow()
				}
				// TODO handle these somewhere else
				keyboard.HandleKeyDown(e.Keysym.Sym)
			case *sdl.KeyUpEvent:
				// TODO handle these somewhere else
				keyboard.HandleKeyUp(e.Keysym.Sym)
			}
		}
		e.Draw()
		sdl.Delay(25)
	}
}

type interpreterFactory struct {
	keyboard   chip8.Keyboard
	keyEvent   chip8.KeyEvent
	randomizer chip8.Randomizer
	speakers   chip8.Speakers
}

func (f *interpreterFactory) New() chip8.Chip8Interpreter {
	i := chip8.NewInterpreter()
	i.SetKeyboard(f.keyboard)
	i.SetKeyEvent(f.keyEvent)
	i.SetRandomizer(f.randomizer)
	i.SetSpeakers(f.speakers)
	return i
}

var maximized bool
var oldW, oldH int
var oldX, oldY int

func maximizeWindow() {
	if !maximized {
		oldW, oldH = window.GetSize()
		oldX, oldY = window.GetPosition()
		window.Maximize()
		window.SetFullscreen(1)
		maximized = true
	}
}

func restoreWindow() {
	if maximized {
		window.SetFullscreen(0)
		window.SetSize(oldW, oldH)
		window.SetPosition(oldX, oldY)
		maximized = false
	}
}

func toDisplayColor(c games.Color) display.Color {
	return display.Color{c.R, c.G, c.B}
}

func setupSdl() error {
	sdl.SetHint(sdl.HINT_RENDER_DRIVER, "opengl")
	sdl.SetHint(sdl.HINT_RENDER_SCALE_QUALITY, "nearest")
	sdl.Init(sdl.INIT_VIDEO | sdl.INIT_AUDIO)

	window, renderer = sdl.CreateWindowAndRenderer(640, 320, sdl.WINDOW_RESIZABLE)
	if window == nil || renderer == nil {
		fmt.Println("Creating window failed.")
		return InitError{}
	}
	window.SetTitle("GO CHIP-8")
	sdl.ShowCursor(0)
	return nil
}

type InitError struct{}

func (_ InitError) Error() string { return "failed to init SDL2" }

func closeSdl() {
	sdl.ShowCursor(1)
	renderer.Destroy()
	window.Destroy()
	sdl.Quit()
}
